﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.IO;
using System.Runtime.InteropServices;

namespace FourPartHarmony2
{
    /// <summary>
    /// 大譜表を描画するコントロール
    /// </summary>
    public partial class GrandStaffControl : UserControl
    {
        private int m_cursorPos = 0;
        private int m_cursorX   = 0;
        private List<Chord> m_chordList = null;

        public GrandStaffControl() {
            InitializeComponent();
            ResizeRedraw = false;

            m_cpcDelegate = null;

            CreateVectorFonts();
            CreateKeySharpFlats();
        }

        public delegate void CursorPositionChangedDelegate(int newCursorPos, int selectedCursorX, Chord selectedChord);
        private CursorPositionChangedDelegate m_cpcDelegate;
        public void SetCursorPositionChangedDelegate(CursorPositionChangedDelegate cpc) {
            m_cpcDelegate = cpc;
        }
        private void CallCursorPositionChanged() {
            if (null != m_cpcDelegate) {
                m_cpcDelegate(m_cursorPos, m_cursorX, (m_chordList.Count == 0) ? null : m_chordList[m_cursorPos]);
            }
        }

        public enum GrandStaffDrawMode
        {
            ChooseChord,
            Music
        }

        GrandStaffDrawMode m_drawMode = GrandStaffDrawMode.ChooseChord;

        public void SetGrandStaffDrawMode(GrandStaffDrawMode mode) {
            m_drawMode = mode;
        }

        enum VectorFontDrawMode
        {
            LineList,
            Bezier,
            Hitofude,
            QuadrangleList
        }

        struct VectorFontInfo
        {
            public List<Point> points;
            public VectorFontDrawMode drawMode;
            public int  lineWidth;

            public VectorFontInfo(VectorFontDrawMode drawMode, int lineWidth)
            {
                points = new List<Point>();
                this.drawMode  = drawMode;
                this.lineWidth = lineWidth;
            }

            public void Paint(Graphics g, Color color, Point pos)
            {
                Pen pen = new Pen(color, lineWidth);
                Brush brush = new SolidBrush(color);
                switch (drawMode) {
                case VectorFontDrawMode.Bezier:
                    for (int i=0; i < points.Count - 3; i += 4) {
                        g.DrawBezier(pen,
                            pos.X + points[i + 0].X, pos.Y + points[i + 0].Y,
                            pos.X + points[i + 1].X, pos.Y + points[i + 1].Y,
                            pos.X + points[i + 2].X, pos.Y + points[i + 2].Y,
                            pos.X + points[i + 3].X, pos.Y + points[i + 3].Y);
                    }
                    break;
                case VectorFontDrawMode.LineList:
                    for (int i=0; i < points.Count - 1; i += 2) {
                        g.DrawLine(pen,
                            points[i].X + pos.X,
                            points[i].Y + pos.Y,
                            points[i + 1].X + pos.X,
                            points[i + 1].Y + pos.Y);
                    }
                    break;
                case VectorFontDrawMode.Hitofude:
                    for (int i=0; i < points.Count - 1; ++i) {
                        g.DrawLine(pen,
                            points[i].X + pos.X,
                            points[i].Y + pos.Y,
                            points[i + 1].X + pos.X,
                            points[i + 1].Y + pos.Y);
                    }
                    break;
                case VectorFontDrawMode.QuadrangleList:
                    for (int i = 0; i < points.Count - 1; i += 4) {
                        Point [] v = new Point[4];
                        v[0] = new Point(points[i].X + pos.X, points[i].Y + pos.Y);
                        v[1] = new Point(points[i + 1].X + pos.X, points[i + 1].Y + pos.Y);
                        v[2] = new Point(points[i + 2].X + pos.X, points[i + 2].Y + pos.Y);
                        v[3] = new Point(points[i + 3].X + pos.X, points[i + 3].Y + pos.Y);
                        g.FillPolygon(brush, v);
                    }
                    break;
                }
            }
        }

        VectorFontInfo smallRomanNumber1 = new VectorFontInfo(VectorFontDrawMode.LineList, 1);
        VectorFontInfo smallRomanNumber2 = new VectorFontInfo(VectorFontDrawMode.LineList, 1);
        VectorFontInfo smallRomanNumber3 = new VectorFontInfo(VectorFontDrawMode.LineList, 1);
        VectorFontInfo smallRomanNumber4 = new VectorFontInfo(VectorFontDrawMode.LineList, 1);
        VectorFontInfo smallRomanNumber5 = new VectorFontInfo(VectorFontDrawMode.LineList, 1);
        VectorFontInfo smallRomanNumber6 = new VectorFontInfo(VectorFontDrawMode.LineList, 1);
        VectorFontInfo smallRomanNumber7 = new VectorFontInfo(VectorFontDrawMode.LineList, 1);
        VectorFontInfo largeRomanNumber1 = new VectorFontInfo(VectorFontDrawMode.LineList, 2);
        VectorFontInfo largeRomanNumber2 = new VectorFontInfo(VectorFontDrawMode.LineList, 2);
        VectorFontInfo largeRomanNumber3 = new VectorFontInfo(VectorFontDrawMode.LineList, 2);
        VectorFontInfo largeRomanNumber4 = new VectorFontInfo(VectorFontDrawMode.LineList, 2);
        VectorFontInfo largeRomanNumber5 = new VectorFontInfo(VectorFontDrawMode.LineList, 2);
        VectorFontInfo largeRomanNumber6 = new VectorFontInfo(VectorFontDrawMode.LineList, 2);
        VectorFontInfo largeRomanNumber7 = new VectorFontInfo(VectorFontDrawMode.LineList, 2);
        VectorFontInfo smallArabicNumber1 = new VectorFontInfo(VectorFontDrawMode.LineList, 1);
        VectorFontInfo smallArabicNumber2 = new VectorFontInfo(VectorFontDrawMode.Hitofude, 1);
        VectorFontInfo smallArabicNumber3 = new VectorFontInfo(VectorFontDrawMode.Hitofude, 1);
        VectorFontInfo smallArabicNumber7 = new VectorFontInfo(VectorFontDrawMode.Hitofude, 1);
        VectorFontInfo smallArabicNumber9 = new VectorFontInfo(VectorFontDrawMode.Hitofude, 1);
        VectorFontInfo smallAdd6 = new VectorFontInfo(VectorFontDrawMode.LineList, 1);
        VectorFontInfo smallAdd46 = new VectorFontInfo(VectorFontDrawMode.LineList, 1);

        VectorFontInfo flatSymbol = new VectorFontInfo(VectorFontDrawMode.Bezier, 2);
        VectorFontInfo sharpSymbol = new VectorFontInfo(VectorFontDrawMode.LineList, 2);
        VectorFontInfo doubleSharpSymbol = new VectorFontInfo(VectorFontDrawMode.QuadrangleList, 1);
        VectorFontInfo naturalSymbol = new VectorFontInfo(VectorFontDrawMode.LineList, 2);
        VectorFontInfo gclef = new VectorFontInfo(VectorFontDrawMode.Bezier, 2);
        VectorFontInfo fclef = new VectorFontInfo(VectorFontDrawMode.Bezier, 2);

        private void CreateVectorFonts()
        {
            // ト音記号。
            // DrawBezier(4n, 4n+1, 4n+2, 4n+3)で描画する。
            gclef.points.Add(new Point(27, 85));
            gclef.points.Add(new Point(23, 83));
            gclef.points.Add(new Point(23, 79));
            gclef.points.Add(new Point(25, 76));
            gclef.points.Add(new Point(25, 76));
            gclef.points.Add(new Point(29, 74));
            gclef.points.Add(new Point(34, 77));
            gclef.points.Add(new Point(35, 81));
            gclef.points.Add(new Point(35, 81));
            gclef.points.Add(new Point(35, 83));
            gclef.points.Add(new Point(33, 88));
            gclef.points.Add(new Point(26, 88));
            gclef.points.Add(new Point(26, 88));
            gclef.points.Add(new Point(21, 87));
            gclef.points.Add(new Point(18, 83));
            gclef.points.Add(new Point(16, 77));
            gclef.points.Add(new Point(16, 77));
            gclef.points.Add(new Point(18, 72));
            gclef.points.Add(new Point(22, 66));
            gclef.points.Add(new Point(25, 63));
            gclef.points.Add(new Point(25, 63));
            gclef.points.Add(new Point(28, 61));
            gclef.points.Add(new Point(31, 54));
            gclef.points.Add(new Point(34, 48));
            gclef.points.Add(new Point(34, 48));
            gclef.points.Add(new Point(34, 44));
            gclef.points.Add(new Point(28, 40));
            gclef.points.Add(new Point(26, 40));
            gclef.points.Add(new Point(26, 40));
            gclef.points.Add(new Point(23, 44));
            gclef.points.Add(new Point(21, 49));
            gclef.points.Add(new Point(23, 54));
            gclef.points.Add(new Point(23, 54));
            gclef.points.Add(new Point(24, 64));
            gclef.points.Add(new Point(27, 72));
            gclef.points.Add(new Point(28, 82));
            gclef.points.Add(new Point(28, 82));
            gclef.points.Add(new Point(30, 91));
            gclef.points.Add(new Point(28, 100));
            gclef.points.Add(new Point(25, 102));
            gclef.points.Add(new Point(25, 102));
            gclef.points.Add(new Point(21, 103));
            gclef.points.Add(new Point(18, 101));
            gclef.points.Add(new Point(17, 97));
            gclef.points.Add(new Point(17, 97));
            gclef.points.Add(new Point(21, 94));
            gclef.points.Add(new Point(22, 96));
            gclef.points.Add(new Point(22, 99));
            gclef.points.Add(new Point(22, 99));
            gclef.points.Add(new Point(23, 101));
            gclef.points.Add(new Point(21, 101));
            gclef.points.Add(new Point(19, 99));
            gclef.points.Add(new Point(19, 99));

            // ヘ音記号。
            // DrawBezier(4n, 4n+1, 4n+2, 4n+3)で描画する。
            fclef.points.Add(new Point(18, 170));
            fclef.points.Add(new Point(19, 166));
            fclef.points.Add(new Point(22, 164));
            fclef.points.Add(new Point(25, 164));
            fclef.points.Add(new Point(25, 164));
            fclef.points.Add(new Point(26, 168));
            fclef.points.Add(new Point(27, 170));
            fclef.points.Add(new Point(26, 172));
            fclef.points.Add(new Point(26, 172));
            fclef.points.Add(new Point(23, 174));
            fclef.points.Add(new Point(18, 172));
            fclef.points.Add(new Point(17, 164));
            fclef.points.Add(new Point(17, 164));
            fclef.points.Add(new Point(20, 159));
            fclef.points.Add(new Point(24, 158));
            fclef.points.Add(new Point(26, 158));
            fclef.points.Add(new Point(26, 158));
            fclef.points.Add(new Point(31, 161));
            fclef.points.Add(new Point(33, 166));
            fclef.points.Add(new Point(35, 172));
            fclef.points.Add(new Point(35, 172));
            fclef.points.Add(new Point(34, 176));
            fclef.points.Add(new Point(31, 182));
            fclef.points.Add(new Point(29, 186));
            fclef.points.Add(new Point(29, 186));
            fclef.points.Add(new Point(27, 189));
            fclef.points.Add(new Point(23, 193));
            fclef.points.Add(new Point(20, 195));
            fclef.points.Add(new Point(20, 195));

            // シャープ記号。
            // DrawLine(2n, 2n+1)で描画する。
            // 音符の玉の中心の座標からの相対で描画する。
            sharpSymbol.points.Add(new Point(-19, -3));
            sharpSymbol.points.Add(new Point(-11, -5));
            sharpSymbol.points.Add(new Point(-19, 6));
            sharpSymbol.points.Add(new Point(-11, 4));
            sharpSymbol.points.Add(new Point(-17, -9));
            sharpSymbol.points.Add(new Point(-17, 11));
            sharpSymbol.points.Add(new Point(-13, -10));
            sharpSymbol.points.Add(new Point(-13, 10));

            // ダブルシャープ
            doubleSharpSymbol.points.Add(new Point(-15, 0));
            doubleSharpSymbol.points.Add(new Point(-19, 1));
            doubleSharpSymbol.points.Add(new Point(-20, 5));
            doubleSharpSymbol.points.Add(new Point(-16, 4));
            doubleSharpSymbol.points.Add(new Point(-15, 0));
            doubleSharpSymbol.points.Add(new Point(-19, -1));
            doubleSharpSymbol.points.Add(new Point(-20, -5));
            doubleSharpSymbol.points.Add(new Point(-16, -4));
            doubleSharpSymbol.points.Add(new Point(-15, 0));
            doubleSharpSymbol.points.Add(new Point(-11, 1));
            doubleSharpSymbol.points.Add(new Point(-10, 5));
            doubleSharpSymbol.points.Add(new Point(-14, 4));
            doubleSharpSymbol.points.Add(new Point(-15, 0));
            doubleSharpSymbol.points.Add(new Point(-11, -1));
            doubleSharpSymbol.points.Add(new Point(-10, -5));
            doubleSharpSymbol.points.Add(new Point(-14, -4));
            doubleSharpSymbol.points.Add(new Point(-15, 0));

            // ナチュラル記号。
            // DrawLine(2n, 2n+1)で描画する。
            // 音符の玉の中心の座標からの相対で描画する。
            naturalSymbol.points.Add(new Point(-17, -4));
            naturalSymbol.points.Add(new Point(-13, -5));
            naturalSymbol.points.Add(new Point(-17, 5));
            naturalSymbol.points.Add(new Point(-13, 4));
            naturalSymbol.points.Add(new Point(-17, -9));
            naturalSymbol.points.Add(new Point(-17, 6));
            naturalSymbol.points.Add(new Point(-13, -6));
            naturalSymbol.points.Add(new Point(-13, 10));

            // フラット記号。
            // DrawBezier(4n, 4n+1, 4n+2, 4n+3)で描画する。
            // 音符の玉の中心の座標からの相対で描画する。
            flatSymbol.points.Add(new Point(-18, -1));
            flatSymbol.points.Add(new Point(-15, -4));
            flatSymbol.points.Add(new Point(-12, -4));
            flatSymbol.points.Add(new Point(-11, -2));
            flatSymbol.points.Add(new Point(-11, -2));
            flatSymbol.points.Add(new Point(-13, 2));
            flatSymbol.points.Add(new Point(-15, 4));
            flatSymbol.points.Add(new Point(-18, 5));
            flatSymbol.points.Add(new Point(-18, 5));
            flatSymbol.points.Add(new Point(-17, -2));
            flatSymbol.points.Add(new Point(-17, -6));
            flatSymbol.points.Add(new Point(-17, -15));

            // 小さいローマ数字。
            // DrawLine(2n, 2n+1)で描画する。
            // 文字の中心が(0, 0)なので音符につけるときは(19, 0)ずらす。
            smallRomanNumber1.points.Add(new Point(0, -5));
            smallRomanNumber1.points.Add(new Point(0, 4));

            smallRomanNumber2.points.Add(new Point(-2, -5));
            smallRomanNumber2.points.Add(new Point(-2, 4));
            smallRomanNumber2.points.Add(new Point(2, -5));
            smallRomanNumber2.points.Add(new Point(2, 4));

            smallRomanNumber3.points.Add(new Point(-3, -5));
            smallRomanNumber3.points.Add(new Point(-3, 4));
            smallRomanNumber3.points.Add(new Point(0, -5));
            smallRomanNumber3.points.Add(new Point(0, 4));
            smallRomanNumber3.points.Add(new Point(3, -5));
            smallRomanNumber3.points.Add(new Point(3, 4));

            smallRomanNumber4.points.Add(new Point(-3, -4));
            smallRomanNumber4.points.Add(new Point(-3, 5));
            smallRomanNumber4.points.Add(new Point(0, -4));
            smallRomanNumber4.points.Add(new Point(3, 5));
            smallRomanNumber4.points.Add(new Point(3, 5));
            smallRomanNumber4.points.Add(new Point(6, -4));

            smallRomanNumber5.points.Add(new Point(-3, -4));
            smallRomanNumber5.points.Add(new Point(0, 5));
            smallRomanNumber5.points.Add(new Point(0, 5));
            smallRomanNumber5.points.Add(new Point(3, -4));

            smallRomanNumber6.points.Add(new Point(-3, -4));
            smallRomanNumber6.points.Add(new Point(0, 5));
            smallRomanNumber6.points.Add(new Point(0, 5));
            smallRomanNumber6.points.Add(new Point(3, -4));
            smallRomanNumber6.points.Add(new Point(6, -4));
            smallRomanNumber6.points.Add(new Point(6, 5));

            smallRomanNumber7.points.Add(new Point(-5, -4));
            smallRomanNumber7.points.Add(new Point(-2, 5));
            smallRomanNumber7.points.Add(new Point(-2, 5));
            smallRomanNumber7.points.Add(new Point(1, -4));
            smallRomanNumber7.points.Add(new Point(4, -4));
            smallRomanNumber7.points.Add(new Point(4, 5));
            smallRomanNumber7.points.Add(new Point(7, -4));
            smallRomanNumber7.points.Add(new Point(7, 5));

            // 大きいローマ数字。音度表示用
            // DrawLine(2n, 2n+1)で描画する。
            largeRomanNumber1.points.Add(new Point(14, 228));
            largeRomanNumber1.points.Add(new Point(14, 251));
            largeRomanNumber1.points.Add(new Point(9, 228));
            largeRomanNumber1.points.Add(new Point(19, 228));
            largeRomanNumber1.points.Add(new Point(9,  251));
            largeRomanNumber1.points.Add(new Point(19, 251));

            largeRomanNumber2.points.Add(new Point(6, 228));
            largeRomanNumber2.points.Add(new Point(6, 251));
            largeRomanNumber2.points.Add(new Point(14, 228));
            largeRomanNumber2.points.Add(new Point(14, 251));
            largeRomanNumber2.points.Add(new Point(2, 228));
            largeRomanNumber2.points.Add(new Point(18, 228));
            largeRomanNumber2.points.Add(new Point(2, 250));
            largeRomanNumber2.points.Add(new Point(18, 250));

            largeRomanNumber3.points.Add(new Point(2, 228));
            largeRomanNumber3.points.Add(new Point(2, 251));
            largeRomanNumber3.points.Add(new Point(8, 228));
            largeRomanNumber3.points.Add(new Point(8, 251));
            largeRomanNumber3.points.Add(new Point(14, 228));
            largeRomanNumber3.points.Add(new Point(14, 251));
            largeRomanNumber3.points.Add(new Point(-2, 228));
            largeRomanNumber3.points.Add(new Point(18, 228));
            largeRomanNumber3.points.Add(new Point(-2, 251));
            largeRomanNumber3.points.Add(new Point(18, 251));

            largeRomanNumber4.points.Add(new Point(1, 228));
            largeRomanNumber4.points.Add(new Point(1, 251));
            largeRomanNumber4.points.Add(new Point(5, 228));
            largeRomanNumber4.points.Add(new Point(11, 251));
            largeRomanNumber4.points.Add(new Point(11, 251));
            largeRomanNumber4.points.Add(new Point(16, 228));
            largeRomanNumber4.points.Add(new Point(-3, 228));
            largeRomanNumber4.points.Add(new Point(20, 228));
            largeRomanNumber4.points.Add(new Point(-3, 251));
            largeRomanNumber4.points.Add(new Point(5,  251));

            largeRomanNumber5.points.Add(new Point(5, 228));
            largeRomanNumber5.points.Add(new Point(11, 251));
            largeRomanNumber5.points.Add(new Point(11, 251));
            largeRomanNumber5.points.Add(new Point(16, 228));
            largeRomanNumber5.points.Add(new Point(1, 228));
            largeRomanNumber5.points.Add(new Point(20, 228));

            largeRomanNumber6.points.Add(new Point(1, 228));
            largeRomanNumber6.points.Add(new Point(6, 251));
            largeRomanNumber6.points.Add(new Point(6, 251));
            largeRomanNumber6.points.Add(new Point(12, 228));
            largeRomanNumber6.points.Add(new Point(16, 228));
            largeRomanNumber6.points.Add(new Point(16, 251));
            largeRomanNumber6.points.Add(new Point(-3, 228));
            largeRomanNumber6.points.Add(new Point(20, 228));
            largeRomanNumber6.points.Add(new Point(12, 251));
            largeRomanNumber6.points.Add(new Point(20, 251));

            largeRomanNumber7.points.Add(new Point(-1, 228));
            largeRomanNumber7.points.Add(new Point(4, 251));
            largeRomanNumber7.points.Add(new Point(4, 251));
            largeRomanNumber7.points.Add(new Point(10, 228));
            largeRomanNumber7.points.Add(new Point(14, 228));
            largeRomanNumber7.points.Add(new Point(14, 251));
            largeRomanNumber7.points.Add(new Point(18, 228));
            largeRomanNumber7.points.Add(new Point(18, 251));
            largeRomanNumber7.points.Add(new Point(-5, 228));
            largeRomanNumber7.points.Add(new Point(22, 228));
            largeRomanNumber7.points.Add(new Point(10, 251));
            largeRomanNumber7.points.Add(new Point(22, 251));

            // 1、2、3はデフォルトでLargeRomanNumberの右上に出る転回番号の位置になっている。
            smallArabicNumber1.points.Add(new Point(23, 232));
            smallArabicNumber1.points.Add(new Point(26, 225));
            smallArabicNumber1.points.Add(new Point(26, 225));
            smallArabicNumber1.points.Add(new Point(26, 238));

            smallArabicNumber2.points.Add(new Point(24, 231));
            smallArabicNumber2.points.Add(new Point(24, 229));
            smallArabicNumber2.points.Add(new Point(24, 227));
            smallArabicNumber2.points.Add(new Point(26, 227));
            smallArabicNumber2.points.Add(new Point(27, 227));
            smallArabicNumber2.points.Add(new Point(29, 227));
            smallArabicNumber2.points.Add(new Point(30, 229));
            smallArabicNumber2.points.Add(new Point(30, 231));
            smallArabicNumber2.points.Add(new Point(29, 232));
            smallArabicNumber2.points.Add(new Point(27, 233));
            smallArabicNumber2.points.Add(new Point(25, 234));
            smallArabicNumber2.points.Add(new Point(23, 236));
            smallArabicNumber2.points.Add(new Point(25, 236));
            smallArabicNumber2.points.Add(new Point(28, 236));
            smallArabicNumber2.points.Add(new Point(29, 236));
            smallArabicNumber2.points.Add(new Point(31, 236));
            smallArabicNumber2.points.Add(new Point(31, 235));

            smallArabicNumber3.points.Add(new Point(22, 231));
            smallArabicNumber3.points.Add(new Point(22, 229));
            smallArabicNumber3.points.Add(new Point(24, 227));
            smallArabicNumber3.points.Add(new Point(28, 227));
            smallArabicNumber3.points.Add(new Point(29, 230));
            smallArabicNumber3.points.Add(new Point(26, 232));
            smallArabicNumber3.points.Add(new Point(26, 233));
            smallArabicNumber3.points.Add(new Point(28, 235));
            smallArabicNumber3.points.Add(new Point(29, 236));
            smallArabicNumber3.points.Add(new Point(28, 239));
            smallArabicNumber3.points.Add(new Point(24, 239));
            smallArabicNumber3.points.Add(new Point(22, 238)); 
            
            // 7、9はデフォルトでLargeRomanNumberの右下に出る形体番号の位置になっている。
            smallArabicNumber7.points.Add(new Point(23, 246));
            smallArabicNumber7.points.Add(new Point(23, 244));
            smallArabicNumber7.points.Add(new Point(23, 242));
            smallArabicNumber7.points.Add(new Point(26, 242));
            smallArabicNumber7.points.Add(new Point(28, 242));
            smallArabicNumber7.points.Add(new Point(29, 242));
            smallArabicNumber7.points.Add(new Point(29, 243));
            smallArabicNumber7.points.Add(new Point(28, 247));
            smallArabicNumber7.points.Add(new Point(27, 249));
            smallArabicNumber7.points.Add(new Point(26, 252));
            smallArabicNumber7.points.Add(new Point(26, 254));

            smallArabicNumber9.points.Add(new Point(29, 246));
            smallArabicNumber9.points.Add(new Point(29, 247));
            smallArabicNumber9.points.Add(new Point(29, 245));
            smallArabicNumber9.points.Add(new Point(28, 243));
            smallArabicNumber9.points.Add(new Point(24, 242));
            smallArabicNumber9.points.Add(new Point(22, 242));
            smallArabicNumber9.points.Add(new Point(21, 244));
            smallArabicNumber9.points.Add(new Point(21, 245));
            smallArabicNumber9.points.Add(new Point(22, 247));
            smallArabicNumber9.points.Add(new Point(24, 249));
            smallArabicNumber9.points.Add(new Point(28, 248));
            smallArabicNumber9.points.Add(new Point(30, 244));
            smallArabicNumber9.points.Add(new Point(30, 242));
            smallArabicNumber9.points.Add(new Point(29, 247));
            smallArabicNumber9.points.Add(new Point(29, 249));
            smallArabicNumber9.points.Add(new Point(28, 253));
            smallArabicNumber9.points.Add(new Point(27, 256));
            smallArabicNumber9.points.Add(new Point(27, 259));

            // 付加6 (-83, -30)して使う
            smallAdd6.points.Add(new Point(112, 274));
            smallAdd6.points.Add(new Point(110, 272));
            smallAdd6.points.Add(new Point(110, 272));
            smallAdd6.points.Add(new Point(107, 272));
            smallAdd6.points.Add(new Point(106, 272));
            smallAdd6.points.Add(new Point(105, 275));
            smallAdd6.points.Add(new Point(104, 276));
            smallAdd6.points.Add(new Point(104, 280));
            smallAdd6.points.Add(new Point(104, 280));
            smallAdd6.points.Add(new Point(106, 282));
            smallAdd6.points.Add(new Point(106, 282));
            smallAdd6.points.Add(new Point(106, 282));
            smallAdd6.points.Add(new Point(106, 282));
            smallAdd6.points.Add(new Point(110, 282));
            smallAdd6.points.Add(new Point(110, 282));
            smallAdd6.points.Add(new Point(112, 279));
            smallAdd6.points.Add(new Point(112, 279));
            smallAdd6.points.Add(new Point(111, 277));
            smallAdd6.points.Add(new Point(112, 277));
            smallAdd6.points.Add(new Point(109, 276));
            smallAdd6.points.Add(new Point(109, 276));
            smallAdd6.points.Add(new Point(107, 276));
            smallAdd6.points.Add(new Point(107, 276));
            smallAdd6.points.Add(new Point(105, 278));
            smallAdd6.points.Add(new Point(97, 278));
            smallAdd6.points.Add(new Point(102, 278));
            smallAdd6.points.Add(new Point(100, 281));
            smallAdd6.points.Add(new Point(100, 275));

            // 付加4-6 (-83, -30)して使う
            smallAdd46.points.Add(new Point(113, 272));
            smallAdd46.points.Add(new Point(112, 270));
            smallAdd46.points.Add(new Point(112, 270));
            smallAdd46.points.Add(new Point(108, 270));
            smallAdd46.points.Add(new Point(108, 270));
            smallAdd46.points.Add(new Point(106, 272));
            smallAdd46.points.Add(new Point(106, 272));
            smallAdd46.points.Add(new Point(105, 275));
            smallAdd46.points.Add(new Point(105, 276));
            smallAdd46.points.Add(new Point(106, 280));
            smallAdd46.points.Add(new Point(106, 280));
            smallAdd46.points.Add(new Point(110, 281));
            smallAdd46.points.Add(new Point(110, 281));
            smallAdd46.points.Add(new Point(113, 279));
            smallAdd46.points.Add(new Point(113, 279));
            smallAdd46.points.Add(new Point(113, 277));
            smallAdd46.points.Add(new Point(113, 277));
            smallAdd46.points.Add(new Point(111, 275));
            smallAdd46.points.Add(new Point(111, 275));
            smallAdd46.points.Add(new Point(108, 275));
            smallAdd46.points.Add(new Point(108, 275));
            smallAdd46.points.Add(new Point(106, 276));
            smallAdd46.points.Add(new Point(111, 283));
            smallAdd46.points.Add(new Point(104, 290));
            smallAdd46.points.Add(new Point(104, 290));
            smallAdd46.points.Add(new Point(114, 290));
            smallAdd46.points.Add(new Point(111, 284));
            smallAdd46.points.Add(new Point(111, 295));
            smallAdd46.points.Add(new Point(99, 283));
            smallAdd46.points.Add(new Point(105, 283));
            smallAdd46.points.Add(new Point(102, 280));
            smallAdd46.points.Add(new Point(102, 287));
        }

        List<Point> keyFlat7 = new List<Point>();
        List<Point> keySharp7 = new List<Point>();

        private void CreateKeySharpFlats()
        {
            int alignx = 4;
            keyFlat7.Add(new Point(58 + alignx, 69));
            keyFlat7.Add(new Point(68 + alignx, 54));
            keyFlat7.Add(new Point(76 + alignx, 74));
            keyFlat7.Add(new Point(85 + alignx, 59));
            keyFlat7.Add(new Point(93 + alignx, 80));
            keyFlat7.Add(new Point(102 + alignx, 64));
            keyFlat7.Add(new Point(111 + alignx, 85));

            keySharp7.Add(new Point(58 + alignx, 49));
            keySharp7.Add(new Point(67 + alignx, 66));
            keySharp7.Add(new Point(75 + alignx, 44));
            keySharp7.Add(new Point(85 + alignx, 60));
            keySharp7.Add(new Point(95 + alignx, 76));
            keySharp7.Add(new Point(104 + alignx, 55));
            keySharp7.Add(new Point(113 + alignx, 69));
        }

        private void PaintKeySharp(Graphics g, Point xy, int num)
        {
            for (int i=0; i < num; ++i) {
                sharpSymbol.Paint(g, Color.Black,
                    new Point(
                        keySharp7[i].X + xy.X,
                        keySharp7[i].Y + xy.Y + CLEF_OFFSET_Y_PIXEL));
            }
            for (int i=0; i < num; ++i) {
                sharpSymbol.Paint(g, Color.Black,
                    new Point(
                        keySharp7[i].X + xy.X,
                        keySharp7[i].Y + xy.Y + CLEF_OFFSET_Y_PIXEL
                        + (F_START_BAR_Y - G_START_BAR_Y + 1) * BAR_INTERVAL_PIXEL));
            }
        }

        private void PaintKeyFlat(Graphics g, Point xy, int num)
        {
            for (int i=0; i < num; ++i) {
                flatSymbol.Paint(g, Color.Black, 
                    new Point(
                        keyFlat7[i].X + xy.X,
                        keyFlat7[i].Y + xy.Y + CLEF_OFFSET_Y_PIXEL));
            }
            for (int i=0; i < num; ++i) {
                flatSymbol.Paint(g, Color.Black,
                    new Point(
                        keyFlat7[i].X + xy.X,
                        keyFlat7[i].Y + xy.Y + CLEF_OFFSET_Y_PIXEL
                        + (F_START_BAR_Y - G_START_BAR_Y + 1) * BAR_INTERVAL_PIXEL));
            }
        }

        public void UpdateChordList(List<Chord> cl, bool bResetCursorPosition)
        {
            m_chordList = cl;

            // カーソル位置を更新する。
            if (bResetCursorPosition) {
                m_cursorPos = 0;
            } else {
                // 和音リストが存在し、カーソル位置が和音リストの外側を指していたら、最後の要素をさすように修正。
                if (0 < m_chordList.Count) {
                    if (m_chordList.Count <= m_cursorPos) {
                        m_cursorPos = m_chordList.Count - 1;
                    }
                }
            }
            CallCursorPositionChanged();
            Invalidate();
        }

        /// <summary>
        /// カーソル位置を1個手前にする。再描画やコールバックイベントは出さない。
        /// すでに先頭の場合は何もしない。
        /// </summary>
        public void DecrementCursorPos() {
            --m_cursorPos;
            if (m_cursorPos < 0) {
                m_cursorPos = 0;
            }
        }

        /// <summary>
        /// カーソル位置を1個進める。再描画やコールバックイベントは出さない。
        /// すでに最後の場合は何もしない。
        /// </summary>
        public void IncrementCursorPos() {
            int numOfChord = m_chordList.Count;

            ++m_cursorPos;
            if (numOfChord <= m_cursorPos) {
                m_cursorPos = numOfChord - 1;
            }
        }

        /// <summary>
        /// カーソル位置を1個戻すが、すでに先頭の場合は最後の要素に移動。
        /// </summary>
        public void ChooseLeftChord()
        {
            if (null == m_chordList)
            {
                return;
            }

            int numOfChord = m_chordList.Count;
            --m_cursorPos;
            if (m_cursorPos < 0)
            {
                m_cursorPos = numOfChord - 1;
            }
            CallCursorPositionChanged();
            Invalidate();
        }

        public void ChooseRightChord() {
            if (null == m_chordList)
            {
                return;
            }
            int numOfChord = m_chordList.Count;
            ++m_cursorPos;
            if (numOfChord <= m_cursorPos)
            {
                m_cursorPos = 0;
            }
            CallCursorPositionChanged();
            Invalidate();
        }

        public Chord GetSelectedChord()
        {
            if (null == m_chordList
                || m_chordList.Count == 0) {
                    return null;
            } 
            return m_chordList.ElementAt(m_cursorPos);
        }

        public Chord GetSelectedChordPrevChord() {
            if (null == m_chordList
                || m_chordList.Count == 0) {
                return null;
            }
            if (m_cursorPos < 1) {
                return null;
            }

            return m_chordList.ElementAt(m_cursorPos-1);
        }

        VectorFontInfo vf = new VectorFontInfo(VectorFontDrawMode.LineList, 1);

        private void AddPoint(int x, int y)
        {
            Point point = new Point(x, y);
            vf.points.Add(point);
            System.Console.WriteLine("===========START");
            foreach (Point p in vf.points) {
                System.Console.WriteLine("keyFlat7.Add(new Point({0}, {1}));",
                    p.X,
                    p.Y);
            }
            System.Console.WriteLine("===========END");
        }
        private void DeletePoint()
        {
            if (vf.points.Count == 0) {
                return;
            }
            vf.points.RemoveAt(vf.points.Count - 1);

            /*
            // 2本ペアになっているので、2本とも消す。
            if (pointList.Count % 2 == 1) {
                DeletePoint();
            }
            */
        }

        private void DrawPointList(Graphics g)
        {
            /*
            PaintKeyFlat(g, xy, 6);
            */

            vf.Paint(g, Color.Black, new Point(0, 0)); 

            /*
            foreach (Point p in vf.points) {
                flatSymbol.Paint(g, Color.Black, p);
            }
            */
        }

        /// <summary>
        /// 二重小節線を描画する。
        /// </summary>
        /// <param name="g"></param>
        /// <param name="x">X座標。</param>
        private void PaintDoubleBarline(Graphics g, ref Point xy)
        {
            Pen pen = new Pen(Color.Black, 1);
            int x = xy.X;
            x -= 2;
            g.DrawLine(pen,
                x, G_START_BAR_Y_PIXEL,
                x, F_END_BAR_Y_PIXEL);
            x += 4;
            g.DrawLine(pen,
                x, G_START_BAR_Y_PIXEL,
                x, F_END_BAR_Y_PIXEL);

            xy.X += 3;
        }

        /*
         * 0
         * 1
         * 2
         * 3
         * 4
         * 5       G_START_BAR_Y----------------------------------
         * 6       -----------------------------------------------
         * 7       -----------------------------------------------
         * 8       G_CLEF_Y---------------------------------------
         * 9       G_END_BAR_Y------------------------------------
         * 10      G_O4C_Y
         * 11
         * 12
         * 13
         * 14
         * 15
         * 16      F_START_BAR_Y ---------------------------------
         * 17      F_CLEF_Y---------------------------------------
         * 18      -----------------------------------------------
         * 19      -----------------------------------------------
         * 20      F_END_BAR_Y------------------------------------
         * 21 MARGIN_W
         * 22      F_O2C_Y
         * 23
         * 24 BOTTOM_Y
         * */
        private const int BAR_INTERVAL_PIXEL = 10;
        private const int NOTE_INTERVAL_Y_PIXEL = BAR_INTERVAL_PIXEL/2;
        private const int G_START_BAR_Y = 8;
        private const int G_END_BAR_Y   = G_START_BAR_Y+4;
        private const int F_START_BAR_Y = G_END_BAR_Y + 7;
        private const int F_END_BAR_Y   = F_START_BAR_Y + 4;
        private const int G_START_BAR_Y_PIXEL = G_START_BAR_Y * BAR_INTERVAL_PIXEL;
        private const int G_END_BAR_Y_PIXEL   = G_END_BAR_Y   * BAR_INTERVAL_PIXEL;
        private const int F_START_BAR_Y_PIXEL = F_START_BAR_Y * BAR_INTERVAL_PIXEL;
        private const int F_END_BAR_Y_PIXEL   = F_END_BAR_Y   * BAR_INTERVAL_PIXEL;
        private const int G_O4C_Y_PIXEL = (G_END_BAR_Y + 1) * BAR_INTERVAL_PIXEL;
        private const int F_O2C_Y_PIXEL = (F_END_BAR_Y + 2) * BAR_INTERVAL_PIXEL;
        private const int MARGIN_W_PIXEL = BAR_INTERVAL_PIXEL * 1;
        private const int CHORD_SPACE_X_PIXEL = 64;
        private const int BOTTOM_Y_PIXEL = G_START_BAR_Y * BAR_INTERVAL_PIXEL + 208;
        private const int NOTE_TO_DEGREE_X_PIXEL = 19;
        private const float NOTE_W_PIXEL = 19.0f * BAR_INTERVAL_PIXEL / 16;
        private const float NOTE_H_PIXEL = 15.0f * BAR_INTERVAL_PIXEL / 16;
        private const float LEDGER_LINE_PIXEL = NOTE_W_PIXEL*1.8f;
        private const int CHORD_PROPERTY_X_PIXEL = 0;
        private const int CHORD_PROPERTY_Y_PIXEL = 5;
        private const int CHORD_TERM_X_PIXEL = 43;
        private const int CHORD_TERM_Y_PIXEL = 60;
        private const int CHORD_PROPERTY_FONT_POINT = 10;
        private const int CHORD_FUNCTION_FONT_POINT = 16;
        private const int CHORD_TERM_FONT_POINT = 8;
        private const int CURSOR_MARGIN_Y_PIXEL = 2;
        private const int CLEF_OFFSET_Y_PIXEL = 3 * BAR_INTERVAL_PIXEL;
        private const int KEY_STRING_X_PIXEL = 1 * BAR_INTERVAL_PIXEL;
        private const int KEY_STRING_Y_PIXEL = F_O2C_Y_PIXEL + BAR_INTERVAL_PIXEL;
        private const int KEY_STRING_FONT_POINT = 12;

        /// <summary>
        /// カーソル表示。
        /// </summary>
        private void PaintCursor(Graphics g, Point xy)
        {
            g.SmoothingMode = SmoothingMode.None;
            Point topLeft = new Point(
                xy.X,
                xy.Y + CURSOR_MARGIN_Y_PIXEL);
            Point bottomRight = new Point(
                topLeft.X + CHORD_SPACE_X_PIXEL,
                xy.Y + BOTTOM_Y_PIXEL);

            Pen pen = new Pen(Color.Black, 2.0f);
            pen.StartCap = LineCap.Square;
            pen.EndCap = LineCap.Square;
            pen.DashStyle = DashStyle.Dash;

            g.DrawLine(pen, topLeft.X, topLeft.Y, topLeft.X, bottomRight.Y);
            g.DrawLine(pen, topLeft.X, bottomRight.Y, bottomRight.X, bottomRight.Y);
            g.DrawLine(pen, bottomRight.X, bottomRight.Y, bottomRight.X, topLeft.Y);
            g.DrawLine(pen, bottomRight.X, topLeft.Y, topLeft.X, topLeft.Y);
        }

        // ト音記号で下のドからの距離
        private int PitchToGClefY(Pitch p)
        {
            if (p.Octave < 3) {
                return -1;
            }
            return (p.Octave - 4) * 7 + p.NoteDistanceFromC();
        }

        //　ヘ音記号で真ん中のドからの距離
        private int PitchToFClefY(Pitch p)
        {
            if (p.Octave < 1)
            {
                return -1;
            }
            return (p.Octave - 2) * 7 + p.NoteDistanceFromC();
        }

        private int PitchAndPartToYPixel(Pitch pitch, Part part)
        {
            switch (part)
            {
            case Part.Sop:
            case Part.Alt:
                return G_O4C_Y_PIXEL - NOTE_INTERVAL_Y_PIXEL * PitchToGClefY(pitch);
            case Part.Ten:
            case Part.Bas:
                return F_O2C_Y_PIXEL - NOTE_INTERVAL_Y_PIXEL * PitchToFClefY(pitch);
            default:
                System.Diagnostics.Debug.Assert(false);
                break;
            }
            return -1;
        }

        static Pitch UPPER_A  = new Pitch(new LnDegInversion(LN.A), 5);
        static Pitch CENTER_C = new Pitch(new LnDegInversion(LN.C), 4);
        static Pitch LOWER_E  = new Pitch(new LnDegInversion(LN.E), 2);

        private void PaintLedgerLines(Graphics g, Point notePos, Pitch pitch, Part part)
        {
            Pen pen = new Pen(Color.Black, 1.0f);

            switch (part) {
            case Part.Sop:
            case Part.Alt:
                {
                    if (PitchToGClefY(UPPER_A) <= PitchToGClefY(pitch))
                    {
                        for (int i = PitchToGClefY(UPPER_A); i <= PitchToGClefY(pitch); i += 2) {
                            Point pos = new Point(notePos.X, G_O4C_Y_PIXEL - NOTE_INTERVAL_Y_PIXEL * i);
                            g.DrawLine(pen,
                                pos.X - LEDGER_LINE_PIXEL / 2,
                                pos.Y,
                                pos.X + LEDGER_LINE_PIXEL / 2,
                                pos.Y);
                        }
                    }
                    else if (PitchToGClefY(pitch) <= PitchToGClefY(CENTER_C))
                    {
                        for (int i = PitchToGClefY(CENTER_C); i >= PitchToGClefY(pitch); i -= 2)
                        {
                            Point pos = new Point(notePos.X, G_O4C_Y_PIXEL - NOTE_INTERVAL_Y_PIXEL * i);
                            g.DrawLine(pen,
                                pos.X - LEDGER_LINE_PIXEL / 2,
                                pos.Y,
                                pos.X + LEDGER_LINE_PIXEL / 2,
                                pos.Y);
                        }
                    }
                }
                break;
            case Part.Ten:
            case Part.Bas:
                {
                    if (PitchToFClefY(CENTER_C) <= PitchToFClefY(pitch))
                    {
                        for (int i = PitchToFClefY(CENTER_C); i <= PitchToFClefY(pitch); i += 2)
                        {
                            Point pos = new Point(notePos.X, F_O2C_Y_PIXEL - NOTE_INTERVAL_Y_PIXEL * i);
                            g.DrawLine(pen,
                                pos.X - LEDGER_LINE_PIXEL / 2,
                                pos.Y,
                                pos.X + LEDGER_LINE_PIXEL / 2,
                                pos.Y);
                        }
                    }
                    else if (PitchToFClefY(pitch) <= PitchToFClefY(LOWER_E))
                    {
                        for (int i = PitchToFClefY(LOWER_E); i >= PitchToFClefY(pitch); i -= 2)
                        {
                            Point pos = new Point(notePos.X, F_O2C_Y_PIXEL - NOTE_INTERVAL_Y_PIXEL * i);
                            g.DrawLine(pen,
                                pos.X - LEDGER_LINE_PIXEL / 2,
                                pos.Y,
                                pos.X + LEDGER_LINE_PIXEL / 2,
                                pos.Y);
                        }
                    }
                }
                break;
                default:
                break;
            }
        }

        /// <summary>
        /// フラットを音符の左に表示。
        /// </summary>
        /// <param name="g"></param>
        /// <param name="notePos">音符の座標</param>
        private void PaintFlat(Graphics g, Point notePos)
        {
            flatSymbol.Paint(g, Color.Black, notePos);
        }

        private void PaintSharp(Graphics g, Point notePos)
        {
            sharpSymbol.Paint(g, Color.Black, notePos);
        }
        private void PaintDoubleSharp(Graphics g, Point notePos) {
            doubleSharpSymbol.Paint(g, Color.Black, notePos);
        }
        private void PaintDoubleFlat(Graphics g, Point notePos) {
            flatSymbol.Paint(g, Color.Black, notePos);
            flatSymbol.Paint(g, Color.Black, new Point(notePos.X-7, notePos.Y));
        }
        private void PaintNatural(Graphics g, Point notePos)
        {
            naturalSymbol.Paint(g, Color.Black, notePos);
        }

        private void PaintDegree(Graphics g, Point notePos, int degree)
        {
            Point degPos = new Point(notePos.X + NOTE_TO_DEGREE_X_PIXEL, notePos.Y);

            switch (degree) {
            case 1: smallRomanNumber1.Paint(g, Color.Black, degPos); break;
            case 2: smallRomanNumber2.Paint(g, Color.Black, degPos); break;
            case 3: smallRomanNumber3.Paint(g, Color.Black, degPos); break;
            case 4: smallRomanNumber4.Paint(g, Color.Black, degPos); break;
            case 5: smallRomanNumber5.Paint(g, Color.Black, degPos); break;
            case 6: smallRomanNumber6.Paint(g, Color.Black, degPos); break;
            case 7: smallRomanNumber7.Paint(g, Color.Black, degPos); break;
            default: return;
            }
        }
        private void PaintChordProperty(Graphics g, Point xy, Progression p)
        {
            Chord chord = p.NowC;
            Color verdictColor = Color.Black;
            string verdictStr = String.Empty;
            switch (chord.Verdict) {
            case VerdictValue.Best:       verdictStr = "最適"; verdictColor = Color.Blue; break;
            case VerdictValue.Good:       verdictStr = "良"; verdictColor = Color.Blue; break;
            case VerdictValue.Okay:       verdictStr = "可能"; verdictColor = Color.Blue; break;
            case VerdictValue.Acceptable: verdictStr = "許"; verdictColor = Color.Blue; break;
            case VerdictValue.Rare:       verdictStr = "まれ"; verdictColor = Color.Blue; break;
            case VerdictValue.NotSoGood:  verdictStr = "なる避"; verdictColor = Color.Red; break;
            case VerdictValue.Avoid:      verdictStr = "避けよ"; verdictColor = Color.Red; break;
            case VerdictValue.Wrong:      verdictStr = "不良"; verdictColor = Color.Red; break;
            case VerdictValue.Prohibited: verdictStr = "禁"; verdictColor = Color.Red; break;
            default: System.Diagnostics.Debug.Assert(false); break;
            }

            StringBuilder sbChordProperty = new StringBuilder();
            if (chord.IsStandard) {
                sbChordProperty.Append("\r\n標準\r\n");
            } else {
                sbChordProperty.Append("\r\n標準外\r\n");
            }
            string sInversion = "根３５７９４６";
            sbChordProperty.Append("(");
            sbChordProperty.Append(sInversion[(int)chord.SopInversion]);
            sbChordProperty.Append(")\r\n");

            switch (chord.PositionOfAChord) {
            case PositionOfAChord.密:  sbChordProperty.Append("密"); break;
            case PositionOfAChord.開:   sbChordProperty.Append("開"); break;
            case PositionOfAChord.Oct: sbChordProperty.Append("Oct"); break;
            default: System.Diagnostics.Debug.Assert(false); break;
            }

            // 終止型
            if (chord.TerminationType != TerminationType.None) {
                string sTermination = string.Empty;
                switch (chord.TerminationType) {
                case TerminationType.Perfect: sTermination = "全"; break;
                case TerminationType.Half: sTermination = "半"; break;
                case TerminationType.Plagal: sTermination = "変"; break;
                case TerminationType.Deceptive: sTermination = "偽"; break;
                default: System.Diagnostics.Debug.Assert(false); break;
                }
                g.DrawString(sTermination,
                    new Font(FontFamily.GenericMonospace, CHORD_PROPERTY_FONT_POINT, FontStyle.Bold),
                    new SolidBrush(Color.Black),
                    new PointF(
                        xy.X + CHORD_TERM_X_PIXEL,
                        xy.Y + CHORD_TERM_Y_PIXEL));
                g.DrawRectangle(new Pen(Color.Black, 1.0f),
                    xy.X + CHORD_TERM_X_PIXEL,
                    xy.Y + CHORD_TERM_Y_PIXEL-2,
                    18, 17);
            }

            // 省略をあらわす斜線
#if false
            for (int i=0,c=0; i<4; ++i) {
                if (3 == i 
                    && chord.NumberOfNotes == NumberOfNotes.Triad) {
                    break;
                }
                if (0 == chord.Upper3CountByInversion((Inversion)i)) {
                    sbChordProperty.Append(sInversion[i]);
                    float dpiScaling =  g.DpiX / 120.0f;
                    if (chord.PositionOfAChord == PositionOfAChord.Oct) {

                        g.DrawLine(new Pen(Color.Black, 2.0f),
                            xy.X + 1.25f * (28 + 13 * c) * dpiScaling,
                            xy.Y + 1.25f * (63) * dpiScaling,
                            xy.X + 1.25f * (38 + 13 * c) * dpiScaling,
                            xy.Y + 1.25f * (50) * dpiScaling);
                    } else {
                        g.DrawLine(new Pen(Color.Black, 2.0f),
                            xy.X + 1.25f * (17 + 13 * c) * dpiScaling,
                            xy.Y + 1.25f * (63) * dpiScaling,
                            xy.X + 1.25f * (28 + 13 * c) * dpiScaling,
                            xy.Y + 1.25f * (50) * dpiScaling);
                    }
                    ++c;
                }
            }
#else
            // 上3声第3音省略の場合だけ表示。
            if (0 == chord.Upper3CountByInversion(Inversion.第3音)) {
                int c = 0;
                sbChordProperty.Append(sInversion[1]);
                float dpiScaling = g.DpiX / 120.0f;
                if (chord.PositionOfAChord == PositionOfAChord.Oct) {

                    g.DrawLine(new Pen(Color.Black, 2.0f),
                        xy.X + 1.25f * (28 + 13 * c) * dpiScaling,
                        xy.Y + 1.25f * (63) * dpiScaling,
                        xy.X + 1.25f * (38 + 13 * c) * dpiScaling,
                        xy.Y + 1.25f * (50) * dpiScaling);
                } else {
                    g.DrawLine(new Pen(Color.Black, 2.0f),
                        xy.X + 1.25f * (17 + 13 * c) * dpiScaling,
                        xy.Y + 1.25f * (63) * dpiScaling,
                        xy.X + 1.25f * (28 + 13 * c) * dpiScaling,
                        xy.Y + 1.25f * (50) * dpiScaling);
                }
            }
#endif
            PointF fontPos = new PointF(
                xy.X + CHORD_PROPERTY_X_PIXEL,
                xy.Y + CHORD_PROPERTY_Y_PIXEL);

            g.DrawString(verdictStr,
                new Font(FontFamily.GenericMonospace, CHORD_PROPERTY_FONT_POINT, FontStyle.Bold),
                new SolidBrush(verdictColor),
                fontPos);
            g.DrawString(sbChordProperty.ToString(),
                new Font(FontFamily.GenericMonospace, CHORD_PROPERTY_FONT_POINT, FontStyle.Bold),
                new SolidBrush(Color.Black),
                fontPos);

            // 和音の度数
            Point degPos = new Point(
                xy.X + CHORD_SPACE_X_PIXEL/2,
                xy.Y + CLEF_OFFSET_Y_PIXEL);
            Point keyDegPos = new Point(
                xy.X + CHORD_SPACE_X_PIXEL / 2 + 11,
                xy.Y + CLEF_OFFSET_Y_PIXEL + 222);
            switch (chord.ChordDegree) {
            case CD.I: largeRomanNumber1.Paint(g, Color.Black, degPos); break;
            case CD.II: largeRomanNumber2.Paint(g, Color.Black, degPos); break;
            case CD.III: largeRomanNumber3.Paint(g, Color.Black, degPos); break;
            case CD.IV: largeRomanNumber4.Paint(g, Color.Black, degPos); break;
            case CD.V: largeRomanNumber5.Paint(g, Color.Black, degPos); break;
            case CD.VI: largeRomanNumber6.Paint(g, Color.Black, degPos); break;
            case CD.VII: largeRomanNumber7.Paint(g, Color.Black, degPos); break;
            case CD.V_V:
                largeRomanNumber5.Paint(g, Color.Black, degPos);
                smallRomanNumber5.Paint(g, Color.Black, keyDegPos);
                break;
            default: System.Diagnostics.Debug.Assert(false); break;
            }
            if (Omission.First == chord.Omission) {
                g.DrawLine(new Pen(Color.Black, 2),
                    degPos.X, degPos.Y + 240, degPos.X + 22, degPos.Y + 232);
            }

            switch (chord.Inversion) {
            case Inversion.根音: break;
            case Inversion.第3音: smallArabicNumber1.Paint(g, Color.Black, degPos); break;
            case Inversion.第5音: smallArabicNumber2.Paint(g, Color.Black, degPos); break;
            case Inversion.第7音: smallArabicNumber3.Paint(g, Color.Black, degPos); break;
            default: System.Diagnostics.Debug.Assert(false); break;
            }

            // 7の和音、9の和音
            switch (chord.NumberOfNotes) {
            case NumberOfNotes.Triad: break;
            case NumberOfNotes.Seventh: smallArabicNumber7.Paint(g, Color.Black, degPos); break;
            case NumberOfNotes.Ninth:   smallArabicNumber9.Paint(g, Color.Black, degPos); break;
            default: System.Diagnostics.Debug.Assert(false); break;
            }

            // 付加6、付加4-6
            switch (chord.AddedTone) {
            case AddedToneType.None: break;
            case AddedToneType.Six:
                smallAdd6.Paint(g, Color.Black,
                    new Point(degPos.X - 82, degPos.Y-30)); break;
            case AddedToneType.SixFour: smallAdd46.Paint(g, Color.Black,
                    new Point(degPos.X - 83, degPos.Y-38)); break;
            default: System.Diagnostics.Debug.Assert(false); break;
            }

            // 準固有の○
            if (chord.Is準固有和音) {
                g.DrawEllipse(new Pen(Color.Black, 1.7f), degPos.X-7.0f, degPos.Y+235.5f, 6, 6);
            }

            // 内部転調
            if (p.PreC == null && p.NowC.KeyRelation != KeyRelation.I調) {
                // いきなり主調とは別の調で始まる場合。こんなのありか？
                PaintModulationStart(g, xy, p.NowC.KeyRelation);
            }
            if (p.PreC != null && p.PreC.KeyRelation != p.NowC.KeyRelation && p.PreC.KeyRelation != KeyRelation.I調) {
                // 内部調終了
                PaintModulationEnd(g, xy);
            }
            if (p.PreC != null && p.PreC.KeyRelation != p.NowC.KeyRelation && p.NowC.KeyRelation != KeyRelation.I調) {
                // 内部調開始
                PaintModulationStart(g, xy, p.NowC.KeyRelation);
            }

            switch (chord.AlterationType) {
            case AlterationType.None:
                break;
            case AlterationType.Lowered:
                if (chord.ChordDegree == CD.V_V) {
                    // V_V 下方変位のひげみたいなの
                    g.DrawLine(new Pen(Color.Black, 2),
                        degPos.X + 2, degPos.Y + 228, degPos.X - 2, degPos.Y + 228 + 8);
                } else {
                    System.Diagnostics.Debug.Assert(false);
                }
                break;
            case AlterationType.Raised:
                if (chord.ChordDegree == CD.V ||
                        chord.ChordDegree == CD.V_V) {
                    // V上方変位のひげみたいなの
                    g.DrawLine(new Pen(Color.Black, 2),
                        degPos.X + 2, degPos.Y + 228, degPos.X + 6, degPos.Y + 228 - 8);
                } else if (chord.ChordDegree == CD.IV) {
                    // IV上方変位のひげみたいなの
                    g.DrawLine(new Pen(Color.Black, 2),
                        degPos.X - 2, degPos.Y + 228, degPos.X + 2, degPos.Y + 228 - 8);
                } else {
                    System.Diagnostics.Debug.Assert(false);
                }
                break;


            case AlterationType.Naples:
                if (chord.ChordDegree == CD.II) {
                    // ナポリII
                    var center = new Point(degPos.X - 4, degPos.Y + 239);
                    g.DrawLine(new Pen(Color.Black, 2),
                        center.X + 1, center.Y, center.X + 8, center.Y);
                } else {
                    System.Diagnostics.Debug.Assert(false);
                }
                break;

            case AlterationType.Dorian:
                // ドリアのIV7
                if (chord.ChordDegree == CD.IV) {
                    var center = new Point(degPos.X - 4, degPos.Y + 239);

                    g.DrawLine(new Pen(Color.Black, 2),
                        center.X - 4, center.Y, center.X + 4, center.Y);
                    g.DrawLine(new Pen(Color.Black, 2),
                        center.X, center.Y - 4, center.X, center.Y + 4);
                } else {
                    System.Diagnostics.Debug.Assert(false);
                }
                break;

            default:
                System.Diagnostics.Debug.Assert(false);
                break;
            }

            // 和音の機能
            StringBuilder sbFunc = new StringBuilder();
            Point funcFontPos = new Point(
                xy.X + CHORD_SPACE_X_PIXEL / 2-10,
                xy.Y + 260);

            if (p.PreC != null && p.PreC.FunctionType == p.NowC.FunctionType) {
                sbFunc.Append("\r\n-");
            } else {
                switch (chord.FunctionType) {
                case FunctionType.Tonic:
                    sbFunc.Append("\r\nT");
                    break;
                case FunctionType.Dominant:
                    sbFunc.Append("\r\nD");
                    break;
                case FunctionType.Subdominant:
                    sbFunc.Append("\r\nS");
                    break;
                default:
                    sbFunc.Append("\r\n");
                    break;
                }
            }

            // カデンツの種類
            switch (chord.CadenceType) {
            case CadenceType.K1:
            case CadenceType.IncompleteK1:
                sbFunc.Append("\r\nK1");
                break;
            case CadenceType.K2:
            case CadenceType.IncompleteK2:
                sbFunc.Append("\r\nK2");
                break;
            case CadenceType.K3:
            case CadenceType.IncompleteK3:
                sbFunc.Append("\r\nK3");
                break;
            default:
                break;
            }
            
            g.DrawString(sbFunc.ToString(),
                new Font(FontFamily.GenericSerif, CHORD_FUNCTION_FONT_POINT),
                new SolidBrush(Color.Black), funcFontPos);

            // 不完全カデンツの線
            switch (chord.CadenceType) {
            case CadenceType.IncompleteK1:
            case CadenceType.IncompleteK2:
            case CadenceType.IncompleteK3:
                g.DrawLine(new Pen(Color.Black, 1),
                    funcFontPos.X + 20, funcFontPos.Y + 62, funcFontPos.X + 30, funcFontPos.Y + 60);
                break;
            default:
                break;
            }

            // Sopの旋律線、Basの旋律線の終止定型進行暗示
            string termStr = "";
            var bas終止定型List = p.GetBas終止定式List();
            foreach (Part終止定式Info t in bas終止定型List) {
                termStr += string.Format("Bas{0}{1}\r\n", t.GetTerminationStringShort(), t.Name);                
            }
            var sop終止定型List = p.GetSop終止定式List();
            foreach (Part終止定式Info t in sop終止定型List) {
                termStr += string.Format("Sop{0}{1}\r\n", t.GetTerminationStringShort(), t.Name);
            }
            var d定型進行 = p.GetD諸和音定型進行();
            if (null != d定型進行) {
                termStr += string.Format("D定{0}{1}\r\n", d定型進行.Sop定型進行名, d定型進行.Bas定型進行名);
            }
            g.DrawString(termStr,
                new Font(FontFamily.GenericSansSerif, CHORD_TERM_FONT_POINT),
                new SolidBrush(Color.Black), new Point(funcFontPos.X, funcFontPos.Y + 70));
        }

        /// <summary>
        /// 内部調開始
        /// </summary>
        private void PaintModulationStart(Graphics g, Point xy, KeyRelation chordKey) {
            var ul = new Point(
                xy.X + 20,
                xy.Y + 236);

            g.DrawArc(new Pen(Color.Black, 1), new Rectangle(ul.X, ul.Y, 44, 66), 135, 90);

            // 調マーク
            string keyString = new KeyRelationInfo(chordKey).DispString();
            Font font = new Font(FontFamily.GenericSerif, CHORD_PROPERTY_FONT_POINT);
            var sSize = g.MeasureString(keyString, font);
            var fontPos = new Point(
                ul.X +2-(int)sSize.Width,
                ul.Y +13);
            g.DrawString(keyString, font, new SolidBrush(Color.Black), fontPos);
        }

        /// <summary>
        /// 内部調終了
        /// </summary>
        private void PaintModulationEnd(Graphics g, Point xy) {
            var ul = new Point(
                xy.X + 19 - 62,
                xy.Y + 236);

            g.DrawArc(new Pen(Color.Black, 1), new Rectangle(ul.X, ul.Y, 44, 66), 315, 90);
        }

        struct Environment
        {
            public Point xy;
            public List<LN> currentSharpList;
            public List<LN> currentFlatList;
            public List<LN> flatListToAdd;
            public List<LN> sharpListToAdd;
            public List<LN> naturalListToAdd;

            public void FlatSharpListUpdate() {
                foreach (LN ln in flatListToAdd) {
                    currentFlatList.Add(ln);
                }
                foreach (LN ln in sharpListToAdd) {
                    currentSharpList.Add(ln);
                }
                foreach (LN ln in naturalListToAdd) {
                    currentFlatList.Remove(ln);
                    currentSharpList.Remove(ln);
                }
                flatListToAdd = null;
                sharpListToAdd = null;
                naturalListToAdd = null;
            }
        }


        private void PaintNote(Graphics g, ref Environment env, Chord chord, Part part)
        {
            Pitch pitch = chord.GetPitch(part);
            SolidBrush brush = new SolidBrush(Color.Black);

            // 玉の中心座標
            Point notePos = new Point(
                env.xy.X + CHORD_SPACE_X_PIXEL/2 - 6,
                env.xy.Y + PitchAndPartToYPixel(pitch, part));

            // 臨時記号の位置
            Point accidentalPos = new Point(notePos.X, notePos.Y);

            if (part == Part.Bas || part == Part.Alt) {
                if (chord.GetPitch((Part)part + 1).AbsIntervalNumberWith(pitch) <= 1) {
                    // 玉の位置が1個上の音符と隣接している(2音以内)ので、下の玉を右にずらす。
                    notePos.X += (int)NOTE_W_PIXEL+3;
                }
                if (chord.GetPitch((Part)part + 1).AbsIntervalNumberWith(pitch) <= 2) {
                    // 玉の位置が1個上の音符と隣接している(3音以内)ので、臨時記号を左にずらす
                    accidentalPos.X -= (int)NOTE_W_PIXEL -2;
                }
            }

            // 玉
            Matrix mIdentity = new Matrix();
            
            // Z軸反時計回りに30度回転してから玉の位置に平行移動するアフィン変換行列を作る。
            // 座標系は右手系で、X軸＋が右方向、Y軸＋が下方向、Z軸＋方向は画面奥の方向。
            Matrix m = new Matrix();
            m.Translate(notePos.X, notePos.Y);
            m.Rotate(-30.0f);

            g.Transform = m;

            // 描画処理で指定する座標系の原点は、回転の中心。
            g.FillEllipse(new SolidBrush(Color.Black),
                - NOTE_W_PIXEL / 2.0f,
                - NOTE_H_PIXEL / 2.0f,
                NOTE_W_PIXEL,
                NOTE_H_PIXEL);
            g.FillEllipse(new SolidBrush(Color.White),
                -(NOTE_W_PIXEL / 2.0f - 1),
                -(NOTE_H_PIXEL / 2.0f - 3),
                (NOTE_W_PIXEL - 2),
                (NOTE_H_PIXEL - 6));

            g.Transform = mIdentity;

            if (pitch.IsFlat() && !env.currentFlatList.Contains(pitch.NaturalLetterName())) {
                // 臨時フラット
                PaintFlat(g, accidentalPos);
                env.flatListToAdd.Add(pitch.NaturalLetterName());
            }
            if (pitch.IsSharp() && !env.currentSharpList.Contains(pitch.NaturalLetterName())) {
                // 臨時シャープ
                PaintSharp(g, accidentalPos);
                env.sharpListToAdd.Add(pitch.NaturalLetterName());
            }
            if (pitch.IsNatural()
                && (env.currentFlatList.Contains(pitch.NaturalLetterName())
                    || env.currentSharpList.Contains(pitch.NaturalLetterName()))) {
                // 臨時ナチュラル
                PaintNatural(g, accidentalPos);
                env.flatListToAdd.Remove(pitch.NaturalLetterName());
                env.sharpListToAdd.Remove(pitch.NaturalLetterName());
                env.naturalListToAdd.Add(pitch.NaturalLetterName());
            }
            if (pitch.IsDoubleSharp()) {
                // ダブルシャープ。常に臨時でつける
                PaintDoubleSharp(g, accidentalPos);
            }
            if (pitch.IsDoubleFlat()) {
                PaintDoubleFlat(g, accidentalPos);
            }

            // 音度
            if (part == Part.Bas || part == Part.Alt ||
                chord.GetPitch((Part)part - 1).AbsIntervalNumberWith(pitch) != 0) {
                // TenかSopの場合で、1つ下の音符と同度の場合音度を出さない。

                PaintDegree(g, new Point(notePos.X - 6, notePos.Y - (int)NOTE_H_PIXEL / 2), pitch.Degree);
            }

            // 補助線
            PaintLedgerLines(g, notePos, pitch, part);

            // 棒
            Pen pen = new Pen(Color.Black, 1.0f);
            switch (part) {
                case Part.Sop:
                case Part.Ten:
                    g.DrawLine(pen,
                        notePos.X + NOTE_W_PIXEL / 2, notePos.Y,
                        notePos.X + NOTE_W_PIXEL / 2, notePos.Y - NOTE_INTERVAL_Y_PIXEL * 7);
                    break;
                case Part.Alt:
                case Part.Bas:
                    g.DrawLine(pen,
                        notePos.X - NOTE_W_PIXEL / 2, notePos.Y,
                        notePos.X - NOTE_W_PIXEL / 2, notePos.Y + NOTE_INTERVAL_Y_PIXEL * 7);
                    break;
            }
        }

        private void PaintChord(Graphics g, ref Environment env, Progression p)
        {
            Chord chord = p.NowC;

            env.flatListToAdd = new List<LN>();
            env.sharpListToAdd = new List<LN>();
            env.naturalListToAdd = new List<LN>();

            g.SmoothingMode = SmoothingMode.HighQuality;
            PaintNote(g, ref env, chord, Part.Sop);
            PaintNote(g, ref env, chord, Part.Alt);
            PaintNote(g, ref env, chord, Part.Ten);
            PaintNote(g, ref env, chord, Part.Bas);

            env.FlatSharpListUpdate();

            // 配置、音度、形体、転回
            PaintChordProperty(g, env.xy, p);

            env.xy.X += CHORD_SPACE_X_PIXEL;
        }

        private void PaintKey(Graphics g, Point xy, MusicKey key)
        {
            MusicKeyInfo mki = new MusicKeyInfo(key, KeyRelation.I調);
            string sKey = mki.GetString() + ":";
            if (0 < mki.FlatNum()) {
                PaintKeyFlat(g, xy, mki.FlatNum());
            }
            if (0 < mki.SharpNum()) {
                PaintKeySharp(g, xy, mki.SharpNum());
            }

            PointF fontPos = new PointF(
                            xy.X + KEY_STRING_X_PIXEL,
                            xy.Y + KEY_STRING_Y_PIXEL);

            g.DrawString(sKey,
                new Font(FontFamily.GenericSerif, KEY_STRING_FONT_POINT),
                new SolidBrush(Color.Black),
                fontPos);
        }

        private void PaintGrandStaff(Graphics g, Point xy, Size wh)
        {
            Pen pen = new Pen(Color.Black, 1.0f);
            pen.StartCap = LineCap.Square;
            pen.EndCap = LineCap.Square;

            g.SmoothingMode = SmoothingMode.None;
            //g.PixelOffsetMode = PixelOffsetMode.HighQuality;

            Point upperRight = new Point(xy.X + wh.Width, xy.Y);

            for (int i=0; i < 5; ++i) {
                Point left = new Point(xy.X + MARGIN_W_PIXEL, xy.Y);
                Point right = new Point(upperRight.X, upperRight.Y);

                left.Y += (i + G_START_BAR_Y) * BAR_INTERVAL_PIXEL;
                right.Y = left.Y;
                g.DrawLine(pen, left, right);
            }
            for (int i=0; i < 5; ++i) {
                Point left = new Point(xy.X + MARGIN_W_PIXEL, xy.Y);
                Point right = new Point(upperRight.X, upperRight.Y);

                left.Y += (i + F_START_BAR_Y) * BAR_INTERVAL_PIXEL;
                right.Y = left.Y;
                g.DrawLine(pen, left, right);
            }
        }

        /// <summary>
        /// 調号
        /// </summary>
        private void PaintClefs(Graphics g, ref Point xy, MusicKey key)
        {
            g.SmoothingMode = SmoothingMode.HighQuality;
            
            Pen pen = new Pen(Color.Black, 2.0f);

            // Gclef
            gclef.Paint(g, Color.Black, new Point(xy.X, xy.Y + CLEF_OFFSET_Y_PIXEL));

            // Fclefはベジェ曲線と2個の点からなる。
            fclef.Paint(g, Color.Black, new Point(xy.X, xy.Y + CLEF_OFFSET_Y_PIXEL));
            g.DrawEllipse(pen, new Rectangle(xy.X+39, xy.Y + CLEF_OFFSET_Y_PIXEL + 165, 2, 2));
            g.DrawEllipse(pen, new Rectangle(xy.X+39, xy.Y + CLEF_OFFSET_Y_PIXEL + 174, 2, 2));

            PaintKey(g, xy, key);

            xy.X += MARGIN_W_PIXEL + (4 + new MusicKeyInfo(key, KeyRelation.I調).FlatSharpNum()) * BAR_INTERVAL_PIXEL;
        }

        //////////////////////////////////////////////////////////////////////////////////////////////
        // イベントハンドラ
        private List<int> chordStartXs = new List<int>();

        private void GrandStaffControl_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            Environment env = new Environment();
            env.xy = new Point(0, 0);

            if (null == m_chordList || m_chordList.Count == 0) {
                PaintGrandStaff(g, new Point(0, 0), new Size(Width, Height));
                PaintClefs(g, ref env.xy, MusicKey.Cdur);
                PaintDoubleBarline(g, ref env.xy); 
                return;
            }

            chordStartXs.Clear();
            for (int i=0; i < m_chordList.Count; ++i) {
                MusicKeyInfo mki = new MusicKeyInfo(m_chordList.ElementAt(i).MusicKey, KeyRelation.I調);

                chordStartXs.Add(env.xy.X);

                if (0 == i
                    || 0 < i && m_chordList.ElementAt(i - 1).MusicKey != m_chordList.ElementAt(i).MusicKey) {
                    // 最初の和音の前または、和音の調が変わる際に調号を表示。
                    env.currentSharpList = mki.CreateSharpLetterNameList();
                    env.currentFlatList = mki.CreateFlatLetterNameList();
                    PaintClefs(g, ref env.xy, mki.InternalKey);
                }

                if (i == m_cursorPos) {
                    PaintCursor(g, env.xy);
                    m_cursorX = env.xy.X;
                }

                PaintChord(g, ref env, new Progression(m_chordList, i));

                switch (m_drawMode) {
                case GrandStaffDrawMode.ChooseChord:
                    // 隣の和音と区切るための二重小節線。
                    // 臨時記号によるシャープやフラットをキャンセル。
                    PaintDoubleBarline(g, ref env.xy);
                    env.currentSharpList = mki.CreateSharpLetterNameList();
                    env.currentFlatList = mki.CreateFlatLetterNameList();
                    break;
                case GrandStaffDrawMode.Music:
                    break;
                default:
                    System.Diagnostics.Debug.Assert(false);
                    break;
                }
            }
            
            if (m_chordList.Count != 0 &&
                m_chordList[m_chordList.Count - 1].KeyRelation != KeyRelation.I調) {
                // 最後の項目が主調でない場合、内部調の閉じカッコを描画。
                PaintModulationEnd(g, env.xy);
            }

            PaintDoubleBarline(g, ref env.xy);
            chordStartXs.Add(env.xy.X);
            ResizeIfNeeded(env.xy.X);

            PaintGrandStaff(g, new Point(0, 0), new Size(Width, Height));

            /* 線描画デバッグ
            DrawPointList(e.Graphics);
             *  */
        }

        private void ResizeIfNeeded(int newWidth) {
            if (Width != newWidth) {
                Width = newWidth;
                MinimumSize = Size;
            }
        }

        private void UpdateCursorPos(int clickedPos)
        {
            if (null == m_chordList) {
                m_cursorPos = 0;
                return;
            }
            for (int i=0; i < chordStartXs.Count-1; ++i) {
                if (chordStartXs[i] <= clickedPos && clickedPos < chordStartXs[i + 1]) {
                    m_cursorPos = i;
                    return;
                }
            }
        }

        public int GetCursorPos()
        {
            return m_cursorPos;
        }

        private void PlayClickedChord()
        {
            if (null != m_chordList && m_cursorPos < m_chordList.Count) {
                // クリックされた和音を鳴らす。
                Chord chord = m_chordList.ElementAt(m_cursorPos);
                chord.PlayNow();
            }
        }

        private void GrandStaffControl_MouseDown(object sender, MouseEventArgs e) {
            /* 線描画デバッグ
            if (e.Button == MouseButtons.Left) {
                AddPoint(e.X, e.Y);
            } else {
                DeletePoint();
            }
             */

            UpdateCursorPos(e.X);
            PlayClickedChord();

            CallCursorPositionChanged();

            // 再描画する。
            Invalidate();
        }

        private void GrandStaffControl_KeyUp(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode) {
            case Keys.Left:
                ChooseLeftChord();
                break;
            case Keys.Right:
                ChooseRightChord();
                break;
            case Keys.Enter:
            case Keys.Space:
                PlayClickedChord();
                break;
            default:
                break;
            }
        }

    }
}
